package com.larry.tinyweb.core.json;

import com.larry.tinyweb.util.DateUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by larry on 16/12/10.
 *
 * @author larry
 */
public class DefaultJson implements IJson {
    private String datePattern = "";

    @Override
    public String toJson(Object val) {
        //字符
        if (val instanceof String ||
            val instanceof Character) return "\"" + specialChar(val.toString()) + "\""; //return "\"" + specialChar(val.toString()) + "\"";

        //实数
        if (val instanceof Number ||
            val instanceof Integer ||
            val instanceof Float ||
            val instanceof Double) return val.toString();

        if (val instanceof Enum)
            return "\"" + val.toString() + "\"";

        //日期
        if (val instanceof Date)
            return "\"" + DateUtil.getTime((Date) val, datePattern) + "\"";

        //map
        if (val instanceof Map)
            return map2Json((Map) val);

        //list
        if (val instanceof List)
            return list2Json((List) val);

        //domain
        return bean2Json(val);
    }

    private String specialChar(String s) {
        if(s == null)
            return "null";
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<s.length(); i++) {
            char c = s.charAt(i);
            switch (c) {
                case '"': sb.append("\\\""); break;
                case '\\': sb.append("\\\\"); break;
                case '\b': sb.append("\\b"); break;
                case '\f': sb.append("\\f"); break;
                case '\n': sb.append("\\n"); break;
                case '\r': sb.append("\\r"); break;
                case '\t': sb.append("\\t"); break;
                default: sb.append(c);
            }
        }
        return sb.toString();
    }

    private String bean2Json(Object val) {
        if (val == null) return "null";
        Map map = new HashMap();
        Method[] methods = val.getClass().getMethods();
        try {
            for (Method m : methods) {
                String methodName = m.getName();
                if (methodName.startsWith("get") && methodName.length() > 3) {
                    String fieldName = getterMethodToField(methodName);
                    if ("class".equals(fieldName)) continue;
                    Object value = m.invoke(val);
                    map.put(fieldName, value);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return map2Json(map);
    }

    private String getterMethodToField(String methodName) {
        methodName = methodName.substring(3);
        return methodName.substring(0, 1).toLowerCase() + methodName.substring(1);
    }

    private String list2Json(List val) {
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        boolean first = true;
        for (Object ele : val) {
            if (first) first = false;
            else sb.append(",");
            sb.append(toJson(ele));
        }
        sb.append("]");
        return sb.toString();
    }

    private String map2Json(Map map) { //, Integer depth
        //if (depth < 0) return "null";
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        boolean first = true;
        for (Object key : map.keySet()) {
            if (first) first = false;
            else sb.append(",");

            sb.append("\"" + key.toString() + "\":");
            sb.append(toJson(map.get(key)));
        }
        sb.append("}");
        return sb.toString();
    }


    @Override
    public <T> T parse(String json, Class<T> clasz) {
        return null;
    }
}
